#include "Application.h"

#include "AmperSensor.h"
#include "Beep.h"
#include "Buttons.h"
#include "GWindow.h"
#include "Leds.h"
#include "NfcCard.h"
#include "PWMControl.h"
#include "TempSensor.h"
#include "Timer.h"
#include "Tools.h"
#include "VBattery.h"
#include "VoltageSensor.h"

#include <math.h>

typedef enum
{
        // 状态：停止充电
        CHARGE_STATE_STOP_CHARGE,
        // 状态：恒压充电
        CHARGE_STATE_IN_SLOW,
        // 状态：恒流充电
        CHARGE_STATE_IN_FAST,
        // 状态：开始准备充电
        CHARGE_STATE_BEGIN,
        // 状态：预订中
        CHARGE_STATE_IN_ORDER,
} ChargeState;

typedef enum
{
        // 事件：无
        CHARGE_EVENT_NONE,
        // 用户设置类事件
        CHARGE_EVENT_SET_MODE,      // 事件：设定了充电模式（用户已设定）
        CHARGE_EVENT_SET_SCHEDULED, // 事件：设定了预定时间（用户已设定）
        CHARGE_EVENT_LOGOUT,

        // 金额不足
        CHARGE_EVENT_INSUFFICIENT_MONEY, // 事件：金额不足

        // 系统触发类事件
        CHARGE_EVENT_SCHEDULE_REACHED, // 事件：预定时间已到（系统触发）
        CHARGE_EVENT_FAST_READY,       // 事件：符合快充条件（系统检测）
        CHARGE_EVENT_SLOW_READY,       // 事件：符合慢充条件（系统检测）
        CHARGE_EVENT_FULLY_CHARGED,    // 事件：电量已充满（系统检测）
} ChargeEvent;

struct _Application
{
        /* 继承 Timer 的能力 */
        Timer parent_instance;
        //
        Network       *net;
        GWidget       *window;
        TempSensor    *temp_sensor[2];
        AmperSensor   *amper_sensor;
        VoltageSensor *voltage_sensor;
        Leds          *leds;
        PWMControl    *pwmc;
        Beep          *beep;
        NfcCard       *nfc_card;
        Buttons       *buttons;
        VBattery      *vbattery;

        /* 测量的温度数据 */
        float temp[2];
        /* 测量的电流数据 */
        float amper;
        /* 测量的电压数据 */
        float voltage;
        /* 用户余额，单位元 */
        float balance;
        /* 设定功率上限 */
        float upower;
        /* 设定当前的功率值 */
        float power_set;
        /* 当前测量的功率值 */
        float power_scale;
        /* 当前电量百分比：0.0 ～ 1.0 */
        float charge_percent;
        /* 快慢充设定转折点 */
        float charge_stage_point;
        /* 当前电价 */
        float price;
        /* 占空比 */
        uint16_t duty_cycle;

        /* 当前用户名的 Hash 值 */
        uint32_t user_hash;

        /* 状态机状态 */
        ChargeState state;
        /* 当前捕获到的程序事件 */
        ChargeEvent event;

        /* 设定充电模式 */
        ChargeMode mode_set;
        /* 当前充电模式 */
        ChargeMode mode_cur;
        /* 当前占用时钟的任务数量 */
        uint8_t tm_task_num;
        /* 预约倒计时设定时间 */
        int8_t order_tm[3];
        /* 已充电时间, [0]: hour, [1]: minute, [2]:second */
        uint8_t charged_tm[3];
        /* 是否在预定中 */
        bool is_in_order;
        /* 充电总开关标志 */
        bool is_charging;
        /* 是否出现故障 */
        bool have_sys_error;
        /* 预约到时后开始/停止充电 */
        bool will_charge_after_schedule_attach;

        /* 时间是否需要更新，0 不需要 0x1 更新预定时间 0x2 更新已充电时间 */
        uint8_t is_times_update;

        /* 右下角显示的额外信息 */
        uint8_t user_info[25];
};

static bool        is_inited = false;
static Application global_app;

/**
 * @brief Application 中，已充电时间和预约时间共用一个时钟原子
 */
static void
app_timer_start(Application *self)
{
        if (self->tm_task_num == 0)
                timer_start(TIMER(self));
        self->tm_task_num += 1;
}

static void
app_timer_stop(Application *self)
{
        if (self->tm_task_num == 0)
                return;
        self->tm_task_num -= 1;
        if (self->tm_task_num == 0)
                timer_stop(TIMER(self));
}

static void
app_set_power(Application *self, float power_set)
{
        self->power_set = power_set > self->upower ? self->upower : power_set;
}

/**
 * @brief 预定时间减少一秒
 * @return 返回是否正在预定
 */
static bool
order_time_reduce_once(Application *self)
{
        if (!self->is_in_order)
                return false;
        self->is_times_update |= 0x1;
        self->order_tm[2] -= 1;
        if (self->order_tm[2] < 0) {
                self->order_tm[1] -= 1;
                if (self->order_tm[1] < 0) {
                        self->order_tm[0] -= 1;
                        if (self->order_tm[0] < 0) {
                                self->order_tm[0] = 0;
                                self->order_tm[1] = 0;
                                self->order_tm[2] = 0;
                                app_timer_stop(self);
                                return false;
                        }
                        self->order_tm[1] = 59;
                }
                self->order_tm[2] = 59;
        }
        return true;
}

/**
 * @brief 已充电时间加一秒
 */
static void
charging_time_add_once(Application *self)
{
        if (!self->is_charging)
                return;
        self->charged_tm[2] += 1;
        if (self->charged_tm[2] >= 60) {
                self->charged_tm[1] += 1;
                if (self->charged_tm[1] >= 60) {
                        self->charged_tm[0] += 1;
                        self->charged_tm[1] = 0;
                }
                self->charged_tm[2] = 0;
        }
}

void
application_connect_network(Application *self, Network *net)
{
        self->net = net;
}

static void
application_set_charge_mode(Application *self, const ChargeMode mode)
{
        self->is_charging = true;
        switch (mode) {
        case CHARGE_MODE_FAST:
                leds_set_mode(self->leds, LEDS_MODE_FAST_MODE);
                self->charge_stage_point = 0.95f;
                self->mode_set           = CHARGE_MODE_FAST;
                break;
        case CHARGE_MODE_SLOW:
                leds_set_mode(self->leds, LEDS_MODE_SLOW_MODE);
                self->charge_stage_point = 0.0f;
                self->mode_set           = CHARGE_MODE_SLOW;
                break;
        case CHARGE_MODE_AUTO:
                leds_set_mode(self->leds, LEDS_MODE_AUTO_MODE);
                self->charge_stage_point = 0.75f;
                self->mode_set           = CHARGE_MODE_AUTO;
                break;
        case CHARGE_MODE_HAND:
                leds_set_mode(self->leds, LEDS_MODE_HAND_MODE);
                /* 手动模式的充电阶段占比待设置 */
                self->charge_stage_point = 0.5f;
                self->mode_set           = CHARGE_MODE_HAND;
                break;
        case CHARGE_MODE_LOGOUT:
                self->mode_set = CHARGE_MODE_LOGOUT;
                leds_set_mode(self->leds, LEDS_MODE_NONE_MODE);
                self->is_charging = false;
                break;
        default:
                self->mode_set = CHARGE_MODE_NONE;
                leds_set_mode(self->leds, LEDS_MODE_NONE_MODE);
                self->is_charging = false;
                break;
        }
        /* 还原预订灯 */
        if (self->is_in_order)
                leds_set_mode(self->leds, LEDS_MODE_WAIT_ORDER);
}

static void
application_set_order_time(Application *self, const uint8_t *p)
{
        self->order_tm[2] = 0;
        /* 小时 */
        self->order_tm[0] = (int8_t)((p[0] - '0') * 10 + (p[1] - '0'));
        /* 分钟 */
        self->order_tm[1] = (int8_t)((p[3] - '0') * 10 + (p[4] - '0'));
        /* 设为全 0 代表取消预约计时 */
        if (self->order_tm[0] == 0 && self->order_tm[1] == 0) {
                leds_set_mode(self->leds, LEDS_MODE_WAIT_FINISH);
                if (self->is_in_order) {
                        self->event = CHARGE_EVENT_SCHEDULE_REACHED;
                        self->will_charge_after_schedule_attach = false;
                        self->is_in_order                       = false;
                        /* 停止预约后将时间归零，即再刷新一次 */
                        self->is_times_update |= 0x1;
                        app_timer_stop(self);
                }
        } else {
                leds_set_mode(self->leds, LEDS_MODE_WAIT_ORDER);
                /* 判断一下是否已经在预约计时了 */
                if (!self->is_in_order) {
                        self->is_in_order = true;
                        /* 开始预约计时 */
                        app_timer_start(self);
                }
        }
}

static float
float_fetch(const uint8_t *p)
{
        float f = 0.0f, rate = 1.0f;
        //
        bool is_pre_dot = true;

        while (*p != ',' && *p != '\0') {
                if (*p == '.') {
                        is_pre_dot = false;
                        p += 1;
                        continue;
                }
                if (is_pre_dot) {
                        f *= 10.0f;
                        f += (float)(*p - '0');
                } else {
                        rate /= 10.0f;
                        f += (float)(*p - '0') * rate;
                }
                p += 1;
        }
        return f;
}

static uint16_t
integer_fetch(const uint8_t *p)
{
        uint16_t u = 0;
        while (*p != ',' && *p != '\0') {
                u = u * 10 + (*p - '0');
                p += 1;
        }
        return u;
}

uint32_t
app_user_hash(const uint8_t *p)
{
        uint32_t sum = 0;
        sum          = 5831;
        while (*p != '\0') {
                sum = (sum << 5) + sum + (uint32_t)*p + 17;
                p += 1;
        }
        return sum;
}

void
app_net_handler_cb(Application *app, const uint8_t *data)
{
        uint32_t now_user_hash = 0;

re_handler:
        const uint8_t key = *data;

        while (*data != '=' && *data != '\0')
                data += 1;
        if (*data == '=')
                data += 1;
        switch (key) {
        /* 直接设置余额，说明新用户已连接到充电桩 */
        case 'a':
                if (now_user_hash == app->user_hash)
                        break;
                app->user_hash     = now_user_hash;
                app->state         = CHARGE_STATE_STOP_CHARGE;
                app->charged_tm[0] = 0;
                app->charged_tm[1] = 0;
                app->charged_tm[2] = 0;
                app->mode_cur      = CHARGE_MODE_NONE;
                app->mode_set      = CHARGE_MODE_NONE;
                app->is_charging   = false;
                leds_set_mode(app->leds, LEDS_MODE_DISABLE);
                app->balance = float_fetch(data);
                break;
        /* balance，充值的余额 */
        case 'b':
                app->balance += float_fetch(data);
                break;
        /* 当前的用户名 */
        case 'g':
                uint8_t *ex_p = app->user_info;
                while (*data != ',' && *data != '\0')
                        *ex_p++ = *data++;
                *ex_p         = '\0';
                now_user_hash = app_user_hash(app->user_info);
                break;
        /* mode，充电模式 */
        case 'm':
                application_set_charge_mode(app, (ChargeMode)*data);
                break;
        /* upower，功率上限 */
        case 'u':
                app->upower = float_fetch(data);
                /* 用户设定功率最大值暂且设为功率上限 */
                app->power_set = app->upower;
                break;
        /* 预定时间到时后启动充电或停止充电 */
        case 'w':
                /* 只有设定了时间才会修改 wcasa */
                if (app->is_in_order)
                        app->will_charge_after_schedule_attach = *data == '1';
                break;
        /* price，当前电价 */
        case 'p':
                app->price = float_fetch(data);
                break;
        /* timeset，设置预定时间 */
        case 't':
                application_set_order_time(app, data);
                break;
        /* debug，当前充电百分比 0 ～ 1.0 */
        case 'i':
                app->charge_percent = float_fetch(data);
                if (app->charge_percent > 1.0f || app->charge_percent < 0)
                        app->charge_percent = 0.5f;
                break;
        /* 设置恒压充电的阈值百分比 */
        case 'c':
                app->charge_stage_point = float_fetch(data);
                if (app->charge_stage_point > 0.95f)
                        app->charge_stage_point = 0.95f;
                else if (app->charge_stage_point < 0.6f)
                        app->charge_stage_point = 0.6f;
                break;
        /* nfc 刷卡出错 */
        case 'e':
                if (*data == 'a')
                        sprintf_b(app->user_info, "\240\241\242\243\244");
                break;
        case 'd':
                TIM_SetCompare3(TIM1, integer_fetch(data));
                break;
        default:
                break;
        }
        while (*data != ',' && *data != '\0')
                data += 1;
        if (*data == '\0')
                return;
        data += 1;
        goto re_handler;
}

/**
 * @brief 捕获当前充电事件
 */
static void
app_catch_event(Application *self)
{
        if (self->event != CHARGE_EVENT_NONE)
                return;

        /* 是否在延时启动预订中 */
        if (self->will_charge_after_schedule_attach) {
                self->event = CHARGE_EVENT_SET_SCHEDULED;
                return;
        }

        /* 充电模式已更新 */
        if (self->mode_set != self->mode_cur) {
                self->event = CHARGE_EVENT_SET_MODE;
                return;
        }

        if (self->balance <= 0.0f) {
                self->balance = 0.0f;
                self->event   = CHARGE_EVENT_INSUFFICIENT_MONEY;
                return;
        }

        if (self->charge_percent >= 1.0f) {
                self->charge_percent = 1.0f;
                self->event          = CHARGE_EVENT_FULLY_CHARGED;
        } else if (self->charge_percent < self->charge_stage_point) {
                self->event = CHARGE_EVENT_FAST_READY;
        } else {
                self->event = CHARGE_EVENT_SLOW_READY;
        }
}

static void
app_event_for_set_mode(Application *self)
{
        if (self->mode_set == CHARGE_MODE_NONE) {
                leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                self->state = CHARGE_STATE_STOP_CHARGE;
                if (self->is_charging) {
                        pwm_control_stop(self->pwmc);
                        self->is_charging = false;
                }
                /* 如果当前已经是停止充电状态，则再按一下停止，就会
                 * 退出用户登陆 */
        } else if (self->mode_set == CHARGE_MODE_LOGOUT) {
                self->user_hash = 0;
                sprintf_b(self->user_info, "\245\246\247");
                network_send(self->net,
                             "zncdz,devType=EMB,msgType=PUB,devID="
                             "esp01s-0016,logout=y");
                self->mode_set = CHARGE_MODE_NONE;
                self->mode_cur = CHARGE_MODE_NONE;
                self->balance = 0.0f;
        } else {
                pwm_control_start(self->pwmc);
                self->is_charging = true;
        }
        self->mode_cur = self->mode_set;
}

static void
app_state_machine_run_once(Application *self)
{
        app_catch_event(self);
        /* 主状态机 */
        switch (self->state) {
                // 0
        case CHARGE_STATE_STOP_CHARGE:
                if (self->event == CHARGE_EVENT_SCHEDULE_REACHED) { // 4
                        // if (self->mode_set == CHARGE_MODE_NONE)
                        // self->mode_set = CHARGE_MODE_AUTO;
                        leds_set_mode(self->leds, LEDS_MODE_WAIT_FINISH);
                        /* 置为正在充电状态 */
                        self->is_charging = true;
                        self->state       = CHARGE_STATE_BEGIN;
                } else if (self->event == CHARGE_EVENT_SET_MODE) { // 1
                        beep_short_twice(self->beep);
                        self->state = CHARGE_STATE_BEGIN;
                } else if (self->event == CHARGE_EVENT_SET_SCHEDULED) { // 2
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        self->is_charging = false;
                        self->mode_cur    = CHARGE_MODE_NONE;
                        pwm_control_stop(self->pwmc);
                        app_timer_stop(self);
                        self->state = CHARGE_STATE_IN_ORDER;
                }
                break;
                // 1
        case CHARGE_STATE_IN_SLOW:
                leds_set_mode(self->leds, LEDS_MODE_SLOW_CHARGE);
                if (self->event == CHARGE_EVENT_SCHEDULE_REACHED) { // 4
                        /* 关闭预定指示灯，打开充电停止指示灯，关闭 PWM 电源 */
                        leds_set_mode(self->leds, LEDS_MODE_WAIT_FINISH);
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        pwm_control_stop(self->pwmc);
                        app_timer_stop(self);
                        self->mode_set    = CHARGE_MODE_NONE;
                        self->is_charging = false;
                        self->state       = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_FULLY_CHARGED || // 7
                           self->event ==
                                   CHARGE_EVENT_INSUFFICIENT_MONEY) { // 3
                        /* 打开停止充电指示灯，关闭 PWM 电源 */
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        pwm_control_stop(self->pwmc);
                        self->is_charging = false;
                        self->mode_set    = CHARGE_MODE_NONE;
                        self->state       = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_SET_MODE) { // 1
                        /* 切换充电模式过程中，关闭已充电计时 */
                        app_timer_stop(self);
                        beep_short_twice(self->beep);
                        self->state = CHARGE_STATE_BEGIN;
                } else if (self->event == CHARGE_EVENT_FAST_READY) { // 5
                        /* 达到快充阶段，调整快充功率大小，PWM
                         * 预校准已在开始充电时进行 */
                        app_set_power(self, 100000.0f);
                        self->state = CHARGE_STATE_IN_FAST;
                } else if (self->event == CHARGE_EVENT_SET_SCHEDULED) { // 2
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        self->is_charging = false;
                        // self->mode_cur    = CHARGE_MODE_NONE;
                        pwm_control_stop(self->pwmc);
                        app_timer_stop(self);
                        self->state = CHARGE_STATE_IN_ORDER;
                }
                break;
                // 2
        case CHARGE_STATE_IN_FAST:
                leds_set_mode(self->leds, LEDS_MODE_FAST_CHARGE);
                if (self->event == CHARGE_EVENT_SCHEDULE_REACHED) { // 4
                        /* 关闭预定指示灯，打开充电停止指示灯，关闭 PWM 电源 */
                        leds_set_mode(self->leds, LEDS_MODE_WAIT_FINISH);
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        beep_long_once(self->beep);
                        pwm_control_stop(self->pwmc);
                        app_timer_stop(self);
                        self->mode_set    = CHARGE_MODE_NONE;
                        self->is_charging = false;
                        self->state       = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_FULLY_CHARGED) { // 7
                        /* 打开停止充电指示灯，关闭 PWM 电源 */
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        beep_long_once(self->beep);
                        pwm_control_stop(self->pwmc);
                        self->is_charging = false;
                        self->mode_set    = CHARGE_MODE_NONE;
                        self->state       = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_SET_MODE) { // 1
                        /* 切换充电模式过程中，关闭已充电计时 */
                        app_timer_stop(self);
                        beep_short_twice(self->beep);
                        self->state = CHARGE_STATE_BEGIN;
                } else if (self->event == CHARGE_EVENT_SLOW_READY) { // 6
                        /* 慢充阶段，调整功率大小，PWM
                         * 预校准已提前进行。慢充的设定功率为 7kW */
                        app_set_power(self, 7000.0f);
                        self->state     = CHARGE_STATE_IN_SLOW;
                } else if (self->event ==
                           CHARGE_EVENT_INSUFFICIENT_MONEY) { // 3
                        /* 打开停止充电指示灯，关闭 PWM 电源 */
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        pwm_control_stop(self->pwmc);
                        self->is_charging = false;
                        self->mode_set    = CHARGE_MODE_NONE;
                        self->state       = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_SET_SCHEDULED) { // 2
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        self->is_charging = false;
                        // self->mode_cur    = CHARGE_MODE_NONE;
                        pwm_control_stop(self->pwmc);
                        app_timer_stop(self);
                        self->state = CHARGE_STATE_IN_ORDER;
                }
                break;
                // 3
        case CHARGE_STATE_BEGIN:
                if (self->event == CHARGE_EVENT_FAST_READY) { // 5
                        leds_set_mode(self->leds, LEDS_MODE_FAST_CHARGE);
                        app_set_power(self, 100000.0f);
                        app_timer_start(self);
                        self->state = CHARGE_STATE_IN_FAST;
                } else if (self->event == CHARGE_EVENT_SLOW_READY) { // 6
                        leds_set_mode(self->leds, LEDS_MODE_SLOW_CHARGE);
                        app_set_power(self, 7000.0f);
                        app_timer_start(self);
                        self->state = CHARGE_STATE_IN_SLOW;
                } else if (self->event == CHARGE_EVENT_FULLY_CHARGED) { // 7
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        pwm_control_stop(self->pwmc);
                        self->state = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_SET_MODE) { // 1
                        app_event_for_set_mode(self);
                        // beep_short_once(self->beep);
                } else if (self->event ==
                           CHARGE_EVENT_INSUFFICIENT_MONEY) { // 3
                        /* 打开停止充电指示灯，关闭 PWM 电源 */
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        pwm_control_stop(self->pwmc);
                        self->is_charging = false;
                        self->mode_set    = CHARGE_MODE_NONE;
                        self->state       = CHARGE_STATE_STOP_CHARGE;
                } else if (self->event == CHARGE_EVENT_SET_SCHEDULED) { // 2
                        leds_set_mode(self->leds, LEDS_MODE_STOP_CHARGE);
                        self->is_charging = false;
                        // self->mode_cur    = CHARGE_MODE_NONE;
                        pwm_control_stop(self->pwmc);
                        app_timer_stop(self);
                        self->state = CHARGE_STATE_IN_ORDER;
                }
                break;
                // 4
        case CHARGE_STATE_IN_ORDER:
                if (self->event == CHARGE_EVENT_SCHEDULE_REACHED) { // 4
                        self->will_charge_after_schedule_attach = false;
                        leds_set_mode(self->leds, LEDS_MODE_WAIT_FINISH);
                        self->is_charging = true;
                        self->state       = CHARGE_STATE_BEGIN;
                }
                break;
        }

        /*
        static unsigned char buffer[50];
        sprintf_b(buffer,
                  "state:%u,event:%u,mode:%u",
                  self->state,
                  self->event,
                  self->mode_cur);
        g_window_set_debug_info(G_WINDOW(self->window), buffer);
        */

        self->event = CHARGE_EVENT_NONE;
}

static const char *
make_publish_messages(const Application *self)
{
        static char buffer[256];
        sprintf_b(buffer,
                  "zncdz,devType=EMB,msgType=PUB,devID=esp01s-0016,progress=%."
                  "3f,power=%.1f,voltage=%.1f,temp=%.1f,balance=%.3f,ctime=%2u:"
                  "%2u:%2u,restime=%2d:%2d:%2d,inrev=%c,mode=%c",
                  self->charge_percent,
                  self->power_scale,
                  self->voltage,
                  self->temp[0],
                  self->balance,
                  self->charged_tm[0],
                  self->charged_tm[1],
                  self->charged_tm[2],
                  self->order_tm[0],
                  self->order_tm[1],
                  self->order_tm[2],
                  self->is_in_order + '0',
                  self->mode_set);
        return buffer;
}

void
application_loop_once(Application *self)
{
        /* 获取传感器数据信息 */
        self->temp[0]     = temp_sensor_get_temp(self->temp_sensor[0]);
        self->temp[1]     = temp_sensor_get_temp(self->temp_sensor[1]);
        self->amper       = amper_sensor_get_amper(self->amper_sensor);
        self->voltage     = voltage_sensor_get_voltage(self->voltage_sensor);
        self->power_scale = self->voltage * self->amper;

        /* 测试 NFC 卡 */
        nfc_card_test(self->nfc_card);

        g_window_set_users_info(G_WINDOW(self->window), self->user_info);

        /* 运行一次状态机 */
        app_state_machine_run_once(self);

        /* 设定屏幕上的信息 */
        g_window_set_temp(G_WINDOW(self->window), self->temp);
        g_window_set_voltage(G_WINDOW(self->window), self->voltage);
        g_window_set_power(G_WINDOW(self->window), self->power_scale);
        g_window_set_balance(G_WINDOW(self->window), self->balance);
        g_window_set_charge_process(G_WINDOW(self->window),
                                    self->charge_percent);
        g_window_set_charge_mode(G_WINDOW(self->window), self->mode_cur);
        g_window_set_price(G_WINDOW(self->window), self->price);
        if (self->is_times_update) {
                if (self->is_times_update & 0x1) {
                        g_window_set_order_time(G_WINDOW(self->window),
                                                self->order_tm);
                }
                if (self->is_times_update & 0x2) {
                        g_window_set_charging_time(G_WINDOW(self->window),
                                                   self->charged_tm);
                }
                self->is_times_update = 0;
        }

        // static unsigned char buffer[30];
        // sprintf_b(buffer, "duty:%u", self->duty_cycle);
        // g_window_set_debug_info(G_WINDOW(self->window), buffer);

        /* 刷新屏幕信息 */
        g_widget_render(self->window, 0, 0, 239, 319);

        /* 推送消息到云平台 */
        network_send(self->net, make_publish_messages(self));
}

/**
 * @brief 50ms 间隔的主时钟回调钩子
 */
static void
app_timer_handler_cb(Application *self)
{
        static uint16_t count1s = 0;

        /* 系统计时计数 */
        if (count1s == 0) {
                if (self->is_in_order && !order_time_reduce_once(self)) {
                        self->event       = CHARGE_EVENT_SCHEDULE_REACHED;
                        self->is_in_order = false;
                }
                if (self->is_charging) {
                        self->is_times_update |= 0x2;
                        charging_time_add_once(self);
                }
                /* 余额采样 */
                if (self->is_charging && self->balance > 0 && self->price > 0 &&
                    self->power_scale > 0) {
                        self->balance -=
                                self->power_scale * self->price / 3600000;
                }
        }

        count1s += 1;
        if (count1s == 20)
                count1s = 0;
}

static void
app_nfc_handler_cb(Application *self, const uint8_t data[])
{
        char card_id[75];
        sprintf_b(self->user_info,
                  "%u-%u-%u-%u",
                  data[0],
                  data[1],
                  data[2],
                  data[3]);

        sprintf_b(card_id,
                  "zncdz,devType=EMB,msgType=PUB,devID=esp01s-0016,nfcid=%u-%u-"
                  "%u-%u",
                  data[0],
                  data[1],
                  data[2],
                  data[3]);
        network_send(self->net, card_id);
}

static void
app_buttons_handler_cb(Application *self, const uint8_t key)
{
        switch (key) {
        case 'f':
                application_set_charge_mode(self, CHARGE_MODE_FAST);
                break;
        case 's':
                application_set_charge_mode(self, CHARGE_MODE_SLOW);
                break;
        case 'a':
                application_set_charge_mode(self, CHARGE_MODE_AUTO);
                break;
        case 'h':
                if (self->mode_set == CHARGE_MODE_NONE)
                        application_set_charge_mode(self, CHARGE_MODE_LOGOUT);
                else
                        application_set_charge_mode(self, CHARGE_MODE_NONE);
                break;
        default:
                break;
        }
}

static void
app_vbattery_handler_cb(Application   *self,
                        const uint16_t quantity,
                        const uint16_t voltage,
                        const uint16_t amper)
{
        const float power    = (float)(voltage * amper) / 10.0f;
        self->charge_percent = (float)quantity / 10000.f;
        pwm_control_set_duty_cycle(self->pwmc, self->duty_cycle);
        if (self->power_set == 0.0f || !self->is_charging) {
                self->duty_cycle = 0;
                vbattery_set_duty_cycle(self->vbattery, self->duty_cycle);
                return;
        }
        if (power > self->power_set)
                self->duty_cycle -= 5;
        else if (power < self->power_set)
                self->duty_cycle += 1;
        if (self->duty_cycle > 1000)
                self->duty_cycle = 1000;
        if (self->duty_cycle < 10)
                self->duty_cycle = 10;
        vbattery_set_duty_cycle(self->vbattery, self->duty_cycle);
}

Application *
application_new_from_global(void)
{
        if (is_inited)
                return &global_app;

        timer_init(TIMER(&global_app),
                   OBJECT_IRQ_HANDLER(app_timer_handler_cb),
                   7200,
                   500);

        global_app.window         = g_window_new();
        global_app.temp_sensor[0] = temp_sensor_new_from_global(0);
        global_app.temp_sensor[1] = temp_sensor_new_from_global(1);
        global_app.amper_sensor   = amper_sensor_new_from_global();
        global_app.voltage_sensor = voltage_sensor_new_from_global();
        global_app.leds           = leds_new_from_global();
        global_app.pwmc           = pwm_control_new_from_global();
        global_app.beep           = beep_new_from_global();
        global_app.nfc_card       = nfc_card_new_from_global();
        global_app.buttons        = buttons_new_from_global();
        global_app.vbattery       = vbattery_new_from_global();

        pwm_control_connect_duty_cycle(global_app.pwmc, &global_app.duty_cycle);
        nfc_card_connect_handler(global_app.nfc_card,
                                 &global_app,
                                 NFC_CARD_HANDLER(app_nfc_handler_cb));
        buttons_connect_handler(global_app.buttons,
                                &global_app,
                                BUTTON_IRQ_HANDLER(app_buttons_handler_cb));
        vbattery_connect_message_handler(
                global_app.vbattery,
                &global_app,
                VBATTERY_MESSAGE_HANDLER(app_vbattery_handler_cb));
        //
        global_app.balance            = 0.0f;
        global_app.net                = NULL;
        global_app.upower             = 100000.0f;
        global_app.power_set          = 0.0f;
        global_app.power_scale        = 0.0f;
        global_app.charge_percent     = 0.0f;
        global_app.charge_stage_point = 0.0f;
        global_app.price              = 1.2f;
        global_app.is_in_order        = false;
        global_app.tm_task_num        = 0;
        global_app.is_charging        = false;
        global_app.is_times_update    = 0;
        global_app.user_hash          = 0;
        global_app.duty_cycle         = 0;
        //
        global_app.will_charge_after_schedule_attach = false;
        //
        global_app.have_sys_error = false;
        global_app.charged_tm[0]  = 0;
        global_app.charged_tm[1]  = 0;
        global_app.charged_tm[2]  = 0;
        global_app.mode_cur       = CHARGE_MODE_NONE;
        global_app.mode_set       = CHARGE_MODE_NONE;
        global_app.state          = CHARGE_STATE_STOP_CHARGE;
        global_app.event          = CHARGE_EVENT_NONE;

        /* 请登陆 */
        sprintf_b(global_app.user_info, "\245\246\247");

        /* 打开 Application 的时钟，使能 Application */
        // app_timer_start(&global_app);
        //
        is_inited = true;
        return &global_app;
}
